from entity import*
from hitbox import*
from player import*
import random

class companion(entity): 
    """The companion, inherits from entity so it has all the properties of entities."""
    def __init__(self,manager):
        entity.__init__(self, manager)
        self.updates = True

        self.rect = pygame.Rect(0,0,40,40) #I am making the companion hitbox the same size as the draw rect. I don't fully understand why it should be smaller.
        self.rect.topleft = (30,10)
        
        self.lhitbox = hitbox(self.rect, -(self.rect.width / 2) - 5,12,10,25)
        self.rhitbox = hitbox(self.rect, +(self.rect.width / 2) + 5,12,10,25)
        self.bhitbox = hitbox(self.rect,0,(self.rect.height / 2) + 5,35,10)
        self.thitbox = hitbox(self.rect,0,-(self.rect.height / 2) + 5,35,10)
        self.toprhitbox = hitbox(self.rect, +(self.rect.width / 2) + 6,-23,10,10)
        self.toplhitbox	= hitbox(self.rect, -(self.rect.width / 2) - 6 ,-23,10,10)
        self.bottomrhitbox = hitbox(self.rect, +(self.rect.width / 2) + 8,30,10,40)
        self.bottomlhitbox = hitbox(self.rect, -(self.rect.width / 2) - 8 ,30,10,40)
        self.lowerhitbox = hitbox(self.rect,0,(self.rect.height / 2) + 90,7,150)
        self.rightairbox = hitbox(self.rect, +(self.rect.width / 2) + 100,75,150,240)
        self.leftairbox = hitbox(self.rect, -(self.rect.width / 2) - 100,75,150,240)

        
        self.right = False			#'Right' key is held
        self.canmoveright = False	#companion can move right
        self.left = False
        self.canmoveleft = False
        self.canmovedown = False #Replaces self.down
        self.canmoveup = True

        self.jump = False		#Companion Presses space
        self.injump = False		#companion is in a jump (moving upward)
        self.holdjump = 0		#Variable that counts upward. Makes sure that if the companion holds down space, they will not walljump after jumpin'
        self.hold = False		#Variable that, when true, adds to 'holdjump'
        self.walljumptimer = 0
        self.previouslyJumping = False #If the companion was holding the jump button in the last frame.

        self.speed = 0
        self.downforce = 0
        self.jumpforce = 0
        
        self.posx1 = 0
        self.jumpcount = 0      #After jumpcount reaches a certain value, the companion will attempt to make a safe landing from the air
        self.detectunder = 0
        self.owner = 0
        
        self.carrying = 0
        self.carrybutton = False
        
        self.fetch = False
        self.chew = False
        self.chewing = False
        self.chewtimer = 0
        #manager.quadtree.insertEntity(self)

    def setplayer(self, entity):
        self.player = entity

    def setfetch(self, entity):
        self.oldfocus = self.player
        self.setplayer(entity)
        self.fetch = True
    
    def setchew(self):
        self.chew = True
        
    def update(self, timeElapsed, manager):
        manager.quadtrees[int(self.layer)].removeEntity(self)
        self.move(manager)
            
        #These lines get entities near the hitboxes specified.
        entitiesnearby = manager.getEntitiesNearby(self.rect) 
        entitiesnearby.extend(manager.getEntitiesNearby(self.lhitbox.rect)) # Could consolidate by making a big rect that fits all
        entitiesnearby.extend(manager.getEntitiesNearby(self.rhitbox.rect))
        entitiesnearby.extend(manager.getEntitiesNearby(self.bhitbox.rect))
        entitiesnearby.extend(manager.getEntitiesNearby(self.toprhitbox.rect))
        entitiesnearby.extend(manager.getEntitiesNearby(self.toplhitbox.rect))
        entitiesnearby.extend(manager.getEntitiesNearby(self.bottomrhitbox.rect))
        entitiesnearby.extend(manager.getEntitiesNearby(self.bottomlhitbox.rect))
        entitiesnearby.extend(manager.getEntitiesNearby(self.lowerhitbox.rect))
        entitiesnearby.extend(manager.getEntitiesNearby(self.rightairbox.rect))
        entitiesnearby.extend(manager.getEntitiesNearby(self.leftairbox.rect))

        colliderects = []
        cielingrects = []
        if(entitiesnearby != None):
            for entity in entitiesnearby:
                if(type(entity) == platform):
                    if (entity.plat == False) and (entity.climb == False):
                        cielingrects.append(entity.rect)
                if(entity != self.owner) and (entity.collides == True) and (entity != self.carrying):
                    colliderects.append(entity.rect)

        rHit = self.rhitbox.rect.collidelist(colliderects)
        bHit = self.bhitbox.rect.collidelist(colliderects)
        tHit = self.thitbox.rect.collidelist(cielingrects)
        lHit = self.lhitbox.rect.collidelist(colliderects)
        toprHit = self.toprhitbox.rect.collidelist(colliderects)
        toplHit = self.toplhitbox.rect.collidelist(colliderects)
        bottomrHit = self.bottomrhitbox.rect.collidelist(colliderects)
        bottomlHit = self.bottomlhitbox.rect.collidelist(colliderects)
        lowerHit = self.lowerhitbox.rect.collidelist(colliderects)
        rightair = self.rightairbox.rect.collidelist(colliderects)
        leftair = self.leftairbox.rect.collidelist(colliderects)
        
        if (self.fetch == False):
            if (self.player.rect.left > (self.rect.left + 100 * random.random() + 50)) and (self.jumpcount < 20) and (self.canmovedown == False):       #Move right if player is right
                self.right = True
            elif (self.jumpcount >= 35) and (rightair != -1) and (leftair == -1):               ##If jumping and there is a platform to the right, move right
                self.right = True
            else:
                self.right = False
                
            if (self.player.rect.right < (self.rect.right - 100 * random.random() - 50)) and (self.jumpcount < 20) and (self.canmovedown == False):     #Move left if player is left
                self.left = True
            elif (self.jumpcount >= 35) and (leftair != -1) and (rightair == -1):               #If jumping and there is a platform to the left, move left
                self.left = True
            else:
                self.left = False

        elif (self.fetch == True):
            if (self.player.rect.left > self.rect.left + 50) and (self.jumpcount < 20) and (self.canmovedown == False):       #Move right if fetch object is right
                self.right = True
            elif (self.jumpcount >= 35) and (rightair != -1) and (leftair == -1):               ##If jumping and there is a platform to the right, move right
                self.right = True
            else:
                self.right = False
                
            if (self.player.rect.right < self.rect.right - 50) and (self.jumpcount < 20) and (self.canmovedown == False):     #Move left if fetch object is left
                self.left = True
            elif (self.jumpcount >= 35) and (leftair != -1) and (rightair == -1):               #If jumping and there is a platform to the left, move left
                self.left = True
            else:
                self.left = False

        
            
        if (self.jumpcount >= 25) and(( (leftair != -1) and (rightair != -1) ) or ( (leftair == -1) and (rightair == -1) ))and not (self.player.rect.top < self.rect.top + 100):    #If both air detectors are recieving signal, or both do not recieve any signal, just go to the player
            if (self.player.rect.left < self.rect.left):
                self.left = True
            elif (self.player.rect.right > self.rect.right):
                self.right = True

        if (self.player.rect.top < self.rect.top - 150) and ( ( (self.player.rect.left - self.rect.left < 100) and (self.player.rect.left - self.rect.left > -100) ) or ( (self.rect.left - self.player.rect.left < 100) and (self.rect.left - self.player.rect.left > -100) ) ):
            self.hold = True
            self.jump = True
            self.previouslyJumping = True
            if self.injump == False:
                self.detectunder = 0
                self.jumpforce = 7		#This number is important. It decides how fast the player moves upwards in a jump.
                self.walljumptimer = 0
     
     
     
        if(rHit != -1):                 #Can I move right?
            self.canmoveright = False
            if self.speed > 0:
                self.speed -= 1
        else:
            self.canmoveright = True

        if(lHit != -1):                 #Can I move left?
            self.canmoveleft = False
            if self.speed < 0:
                self.speed += 1
        else:
            self.canmoveleft = True

        if(bHit != -1):                 #Am I on the ground?
            self.canmovedown = False
            self.downforce = 0
            self.jumpcount = 0
            self.detectunder = 0
        else:
            self.canmovedown = True
            self.jumpcount += 1       
            
        if(toprHit == -1) and (rHit != -1) and (self.right == True):		#Conditions for climbing up an edge on right side
            if self.jumpforce < 3:
                self.jumpforce += .5
            self.speed = 1
            self.canmovedown = False
            self.injump = True
            
        elif(toprHit != -1) and (rHit != -1) and (self.right == True):      #Conditions for jumping right when hitting a wall
            self.hold = True
            self.jump = True
            self.previouslyJumping = True
            if self.injump == False:
                self.detectunder = 0
                self.jumpforce = 7
                self.walljumptimer = 0

        if(toplHit == -1) and (lHit != -1) and (self.left == True):			#Conditions for climbing up an edge on left side
            if self.jumpforce < 3:
                self.jumpforce += .5
            self.speed = -1
            self.canmovedown = False
            self.injump = True


        elif(toplHit != -1) and (lHit != -1) and (self.left == True):       #Conditions for jumping left when hitting a wall
            self.hold = True
            self.jump = True
            self.previouslyJumping = True
            if self.injump == False:
                self.detectunder = 0
                self.jumpforce = 7
                self.walljumptimer = 0
 
 
        if(toprHit == -1) and (rHit != -1) and (self.injump == True):		#Conditions for climbing up an edge on right side in midair
            self.right = True
            if self.jumpforce < 3:
                self.jumpforce += .5
            self.speed = 1
            self.canmovedown = False
            self.injump = True
            

        if(toplHit == -1) and (lHit != -1) and (self.injump == True):			#Conditions for climbing up an edge on left side in midair
            self.left = True
            if self.jumpforce < 3:
                self.jumpforce += .5
            self.speed = -1
            self.canmovedown = False
            self.injump = True

 
 
        #Conditions for jumping when going off a ledge
        if((bottomrHit == -1) and (bHit != -1) and (self.speed > .5)) or ((bottomlHit == -1) and (bHit != -1) and (self.speed < .5)):
            if not (self.player.rect.top > self.rect.top + 40): #Tells the companion not to jump if the player is below
                    if(self.right == True) or (self.left == True):
                        self.hold = True
                        self.jump = True
                        self.previouslyJumping = True
                        if self.injump == False:
                            self.detectunder = 0
                            self.jumpforce = 7.5		#This number is important. It decides how fast the player moves upwards in a jump.
                            self.walljumptimer = 0
        
        
        if (lowerHit == -1) and (self.detectunder == 0):        #Detectunder is used to tell when the jump should stop
            self.detectunder = 1
        
        if (lowerHit != -1) and ((self.detectunder == 1) or (self.detectunder == 2)):
            if (self.speed > .2):
                self.left = True
            if (self.speed < -.2):
                self.right = True
            self.jump = False
            self.hold = False
            if (self.detectunder == 1):
                self.jumpforce /= 2	
                self.detectunder = 2
            self.previouslyJumping = True #The companion was not holding the jump key in the last frame.
            
            
            
        #Conditions for a walljump         
        if (self.canwalljump == True) and ((lowerHit == -1) or (self.player.rect.top < self.rect.top - 100)) and ((toprHit != -1) or (toplHit != -1)) and (self.downforce > 0) and not (self.player.rect.top > self.rect.top):
            if ((rHit != -1) and (leftair != -1)) or((lHit != -1) and (rightair != -1)) or (self.player.rect.top  < self.rect.top - 200) or (self.player.rect.left  < self.rect.left - 250) or (self.player.rect.right  < self.rect.right + 250):
                    self.jump = True
                    self.injump = True
                    self.jumpforce = 7
                    self.detectunder = 0
                    if self.canmoveright == False:
                        self.speed -= 3
                    if self.canmoveleft == False:
                        self.speed += 3
            
        if (tHit != -1):            #Can I move up?
            self.canmoveup = False
        else:
            self.canmoveup = True
            
        if(self.canmoveup != True):     
            self.jumpforce = 0
            
            
        if (self.carrybutton == True):
            self.carrybutton = False
            
            
            #Fetch Code:
            
        if (self.fetch == True):
            if (self.player.rect.colliderect(self.rect)):
                if (self.speed < .2 and self.speed > -.2):
                    if (self.chew == False):
                        self.setplayer(self.oldfocus)
                        self.carrybutton = True
                        self.fetch = False
                    elif (self.chew == True):
                        self.chewing = True
                        self.fetch = False
       
        if (self.chewing == True):
            if (self.chewtimer < 240):
                self.chewtimer += 1
                self.speed = 0
                self.player.canbecarried = False
            if (self.chewtimer >= 240):
                self.player.delete(manager)
                self.player.canbecarried = True
                self.setplayer(self.oldfocus)
                self.chew = False     
                self.chewing = False      
                self.chewtimer = 0
            
        if (self.speed < .2 and self.speed > -.2) and (self.carrying != 0):
            self.carrybutton = True
                
        manager.quadtrees[int(self.layer)].insertEntity(self)

    def draw(self, camera, screen, manager):
        entity.draw(self, camera, screen, manager)
        """self.lhitbox.draw(camera, screen)
        self.rhitbox.draw(camera, screen)
        self.bhitbox.draw(camera, screen)
        self.thitbox.draw(camera, screen)
        self.toprhitbox.draw(camera, screen)
        self.toplhitbox.draw(camera, screen)
        self.bottomrhitbox.draw(camera, screen)
        self.bottomlhitbox.draw(camera, screen)
        self.lowerhitbox.draw(camera, screen)
        self.rightairbox.draw(camera, screen)
        self.leftairbox.draw(camera, screen)"""
        
    def move(self, manager):
        self.moveBy(self.speed,0)
        
        self.lhitbox.update()
        self.rhitbox.update()
        self.bhitbox.update()
        self.thitbox.update()
        self.toprhitbox.update()
        self.toplhitbox.update()
        self.bottomrhitbox.update()
        self.bottomlhitbox.update()
        self.lowerhitbox.update()
        self.rightairbox.update()
        self.leftairbox.update()#Adjust hitboxes after move

        #If on ground, handle like this.
        if self.injump == False and self.canmovedown == False:
            if self.canmoveright == True:
                if self.right == True:
                    if self.speed < 3:
                        self.speed += .5

            if self.canmoveleft == True:
                if self.left == True:
                    if self.speed > -3:
                        self.speed -= .5
            if self.left == False and self.right == False:
                if self.speed > 0:
                    self.speed -= .1
                if self.speed < 0:
                    self.speed += .1
        
        #If in air, handle like tihs.
        if self.injump == True or self.canmovedown == True:
            if self.canmoveright == True:
                if self.right == True:
                    if self.speed < 3:
                        self.speed += .15
            if self.canmoveleft == True:
                if self.left == True:
                    if self.speed > -3:
                        self.speed -= .15
            
        #If falling, apply downforce that grows with time and stops at 4.
        if self.canmovedown == True and self.injump == False:
            if self.downforce < 4:
                self.downforce += .2
                self.walljumptimer = 20
            self.rect.move_ip(0,self.downforce  / manager.fpsupdate)
            self.lhitbox.update()
            self.rhitbox.update()
            self.bhitbox.update()
            self.toprhitbox.update()
            self.toplhitbox.update()
            

        #If not jumping, activate jump!
        if self.injump == False and self.canmovedown == False:
            if self.jump == True:
                self.injump = True
                
        #If jumping, apply these forces:
        if self.injump == True:
            if self.jumpforce > 0:
                self.canmovedown == False
                self.rect.move_ip(0,-self.jumpforce  / manager.fpsupdate)	
                self.jumpforce -= .2
                self.lhitbox.update()
                self.rhitbox.update()
                self.bhitbox.update()
                self.toprhitbox.update()
                self.toplhitbox.update()
                
        #If there is no jumpforce left, take the companion out of jump mode.
        if self.jumpforce <= 0:
                self.injump = False
        
        #These two If statements make it so you slide slower while going up or down a wall
        if (self.canmoveright == False or self.canmoveleft == False) and self.injump == True:
            self.jumpforce -= .05
        if (self.canmoveright == False or self.canmoveleft == False) and self.canmovedown == True:
            if self.downforce > .15:
                self.downforce -= .15
        
        
        #Test if the companion is able to walljump based on a timer
        if self.walljumptimer > 10:
            self.canwalljump = True
        else:
            self.canwalljump = False
            
        if self.walljumptimer < 20:
            self.walljumptimer += 1
            

        #Execute the walljump if companion is in position
        if self.canwalljump == True  and self.holdjump == 0:
            if (self.canmoveright == False or self.canmoveleft == False) and (self.canmovedown == True or self.injump == True):
                if self.jump == True:
                    self.injump = True
                    self.jumpforce = 7
                    if self.canmoveright == False:
                        self.speed -= 3.5
                    if self.canmoveleft == False:
                        self.speed += 3.5
        #Limit Companion speed (fixes a bug or two)
        if self.speed < -3.5:
            self.speed = -3.5
        if self.speed > 3.5:
            self.speed = 3.5
        
        #Holdin jump key
        if self.hold == True:
            self.holdjump = 1
        else:
            self.holdjump = 0

    @staticmethod
    def onLoad(manager, saveData):
        me = entity.onLoad(manager, saveData)
        me.player = manager.game.player
        me.player.dog = me
        manager.game.dog = me
        return me

